#ifndef __COMM_HPP__
#define __COMM_HPP__

#include<iostream>
#include<unistd.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>
#include <sys/stat.h>
#include<cstring>
#include<cassert>
using namespace std;

// #define PATH_NAME "."
// #define PROJECT_ID 666
static const char PATH_NAME[] = ".";    // 自定义路径
static const int PROJECT_ID = 0x666;      // 自定义的id
static const size_t gsize = 4096;       // 共享内存大小（单位/字节）

key_t getKey()
{
    key_t key = ftok(PATH_NAME, PROJECT_ID);  //  调用函数来获取key值，这样的key冲突较小
    if(key == -1)
    {
        perror("flok"); 
        exit(1);
    }
    return key;
}
int serverShm(key_t k, size_t size, int flag)
{
    int id = shmget(k, size, flag);
    if(id == -1)
    {
        perror("serverShm");
        exit(2);
    }
    return id;
}
int createShm()
{
    key_t k = getKey();
    umask(0);  // 设置默认权限
    return serverShm(k, gsize, IPC_CREAT | IPC_EXCL | 0666);  // 保证开辟的共享内存一定是最新的
}
int getShm()
{
    key_t k = getKey();
    return serverShm(k, gsize, IPC_CREAT);
}
char* attachShm(int shmId)
{
    char* pshm = (char*)shmat(shmId, nullptr, 0);
    if(pshm == (char*)-1)
    {
        perror("shmat");
        exit(-1);
    }
    return pshm;
}
int detectShm(char* pshm)
{
    int n = shmdt(pshm);
    if(n == -1)
    {
        perror("shmdt");
        exit(-1);
    }
}
void delShm(int id)
{
    // 删除指令IPC_RMID
    shmctl(id, IPC_RMID, nullptr);
}

// 对共享内存的封装
class initShm
{
public:
    initShm(int t):type(t)
    {
        if(type)
            id = createShm();   // （服务端）开辟共享内存
        else
            id = getShm();      // （客户端）接受标识符
        pshm = attachShm(id);  // 关联共享内存，得到共享内存的虚拟地址
    }
    char* getPshm()
    {
        return pshm;
    }
    ~initShm()
    {
        detectShm(pshm);    // 关闭联系
        if(type)
        delShm(id);         // 释放共享内存（默认服务端开启和释放）
    }

private:
    int type;   // 判断类型，是客户端0，还是服务端1
    int id;     // 共享内存的标识符
    char* pshm; // 共享内存的虚拟地址
};
#endif